#include "ftpclient.h"
#include "ftpprotocol.h"
#include <QThread>
#include <QFile>
#include <QFileInfo>
#include <QMutex>
#include <QTimer>
#include <QRegularExpression>

// 定义静态常量
const QString FtpClient::LOG_PREFIX = "[FTP Client]";

// 为了解决Private类的元对象问题，需要在类定义后添加Q_OBJECT的实现支持
class FtpClient::Private : public QObject
{
    Q_OBJECT
public:
    Private(FtpClient *parent)
        : QObject(parent),
          ftpProtocol(nullptr),
          isConnected(false),
          q(parent),
          currentPort(21),
          currentTransferFile(nullptr),
          totalTransferSize(0),
          transferredSize(0),
          usePasv(false),  //缺省使用PORT模式
          usePasv2(false) // 缺省使用PASV模式
    {
        // 创建工作线程
        workerThread.setObjectName("FtpWorkerThread");
        
        // 创建协议处理器并移动到工作线程
        ftpProtocol = new FtpProtocol();
        ftpProtocol->moveToThread(&workerThread);
        
        // 连接信号槽
        connect(&workerThread, &QThread::finished, ftpProtocol, &QObject::deleteLater);
        connect(ftpProtocol, &FtpProtocol::responseReceived, this, &Private::onResponseReceived, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::dataConnectionEstablished, this, &Private::onDataConnectionEstablished, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::error, this, &Private::onProtocolError, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::listDataReceived, this, &Private::onListDataReceived, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::fileDataReceived, this, &Private::onFileDataReceived, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::dataConnectionReady, this, &Private::onDataConnectionReady, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::controlConnectionClosed, this, &Private::onControlConnectionClosed, Qt::QueuedConnection);
        connect(ftpProtocol, &FtpProtocol::downloadProgress,this, &FtpClient::Private::onDownloadProgress, Qt::QueuedConnection);
        // 启动工作线程
        workerThread.start();
    }
    
    ~Private()
    {
         // 停止工作线程
        workerThread.quit();
        workerThread.wait();

        if (currentTransferFile) {
            delete currentTransferFile;
        }
    }
    
    // 成员变量
    FtpProtocol *ftpProtocol;
    bool isConnected;
    QString currentHost;
    QString currentUsername;
    QString currentPassword;
    int currentPort;
    bool usePasv;  //是否使用PASV模式(相对Port)
    bool usePasv2; //是否使用PASV2模式(相对PASV)

    QString pendingCommand; // 待执行的命令
    QString pendingCommandArg; // 命令参数

        
    // 当前操作相关
    QString currentOperation;
    QString currentRemoteFile;
    QString currentLocalFile;
    QFile *currentTransferFile;
    qint64 totalTransferSize;
    qint64 transferredSize;
    
    // 线程相关
    QThread workerThread;
    QMutex mutex;
    
    QList<QStringList> receivedFileList;
    
    // 父对象指针
    FtpClient *q;
    
    // 处理响应
    void onResponseReceived(int code, const QString &message);
    void onDataConnectionEstablished();
    void onProtocolError(const QString &message);
    void readAndSendFileData();
public slots:
    // 执行各种FTP操作的槽函数
    void doConnect();
    void doChangeDirectory();
    void doListFiles(const QString &path);
    void doDownload(const QString &remoteFile, const QString &localPath,qint64 filesize);
    void doUpload(const QString &localFile, const QString &remotePath);
    void doDelete(const QString &fileName);
    
    // 数据传输相关
    void startFileTransfer();
    void handleDataTransfer();
    void finishFileTransfer(bool success, const QString &message = "");
    void sendNextCommand();
    void onListDataReceived(const QList<QStringList>& fileInfoList);
    void onFileDataReceived(const QByteArray& data);
    void onDataConnectionReady();
    void onControlConnectionClosed();
    void onDownloadProgress(qint64 downloaded, QString filename);
};

// 实现Private类的槽函数
void FtpClient::Private::onResponseReceived(int code, const QString &message)
{
    FTP_CLIENT_DEBUG_FMT("收到响应:%d %s", code, message.trimmed().toUtf8().constData());
    
	// 处理目录切换响应
	if (pendingCommand == "CWD") {
        if (code >= 200 && code < 300) {
            FTP_CLIENT_DEBUG_FMT("目录切换成功: %s", pendingCommandArg.toUtf8().constData());
            emit q->directoryChanged(true, pendingCommandArg, message);
        } else {
            FTP_CLIENT_DEBUG_FMT("目录切换失败: %s", message.toUtf8().constData());
            emit q->directoryChanged(false, pendingCommandArg, message);
        }
        return;
    }
	
	// 处理PASV / PORT / PASV2响应
	if ((code == 227 || code == 225 || code == 200) && !pendingCommand.isEmpty()) {
		// PASV/PORT/PASV2命令成功，建立数据连接并发送下一个命令
		QMetaObject::invokeMethod(ftpProtocol, [this]() {
			if (ftpProtocol->establishDataConnection()) {
				// 数据连接建立成功，发送下一个命令
				if (pendingCommand == "LIST") {
					ftpProtocol->sendLIST(pendingCommandArg);
				}
				else if (pendingCommand == "RETR") {
					ftpProtocol->sendRETR(pendingCommandArg, currentLocalFile);
				}
				else if (pendingCommand == "STOR") {
					ftpProtocol->sendSTOR(pendingCommandArg);
				}

				// 清空待执行命令
				QMetaObject::invokeMethod(this, [this]() {
					pendingCommand.clear();
					pendingCommandArg.clear();
					}, Qt::QueuedConnection);
			}
			else {
				// 数据连接建立失败
				QMetaObject::invokeMethod(this, [this]() {
					if (pendingCommand == "LIST") {
						emit q->fileListReceived(false, QList<QStringList>(), "数据连接建立失败");
					}
					else if (pendingCommand == "RETR") {
						finishFileTransfer(false, "数据连接建立失败");
					}
					else if (pendingCommand == "STOR") {
						finishFileTransfer(false, "数据连接建立失败");
					}
					pendingCommand.clear();
					pendingCommandArg.clear();
					}, Qt::QueuedConnection);
			}
			}, Qt::QueuedConnection);
		return;
	}
    
    // 根据不同的操作和响应码处理
    if (currentOperation == "CONNECT") {
        if (code == 220) {
            FTP_CLIENT_DEBUG_FMT("连接成功，发送USER命令");
            ftpProtocol->sendUSER(currentUsername);
        } else if (code == 331) {
            FTP_CLIENT_DEBUG_FMT("需要密码，发送PASS命令");
            ftpProtocol->sendPASS(currentPassword);
        } else if (code == 230) {
            FTP_CLIENT_DEBUG_FMT("登录成功");
            isConnected = true;
            emit q->connected(true, "登录成功");
        } else {
            FTP_CLIENT_DEBUG_FMT("连接失败:%s", message.toUtf8().constData());
            emit q->connected(false, message);
        }
	}
	else if (currentOperation == "LIST") {
        if (150 != code) {
            if (226 == code) {
                emit q->fileListReceived(true, QList<QStringList>(), message);
            }
            else {
                emit q->fileListReceived(false, QList<QStringList>(), message);
            }
        }
	}
	else if (currentOperation == "RETR") {
        if (code == 150 || code == 125) {
            // 开始下载
            startFileTransfer();
        } else if (code == 226) {
            // 下载完成,控制通道发送数据通道关闭消息，不做停止文件传输处理，因为可能控制通道数据还没接收完
            //QTimer::singleShot(1000, [this]() {finishFileTransfer(true, "下载成功");});
        } else {
            finishFileTransfer(false, message);
        }
    } else if (currentOperation == "STOR") {
        if (code == 150 || code == 125) {
            // 开始上传
            startFileTransfer();
        } else if (code == 226) {
            // 上传完成
            finishFileTransfer(true, "上传成功");
        } else {
            if (code == 200 && usePasv2) {
              //in passvmode 2 is ok for FISTOR
             finishFileTransfer(true, "上传成功");
            }
            else {
                finishFileTransfer(false, message);
            }
        }
    } else if (currentOperation == "DELE") {
        if (code == 250) {
            // 删除成功
            emit q->deleteFinished(true, currentRemoteFile, "删除成功");
        } else {
            emit q->deleteFinished(false, currentRemoteFile, message);
        }
    }
}

void FtpClient::Private::onDataConnectionEstablished()
{
    // 数据连接已建立，开始处理数据
    handleDataTransfer();
}

void FtpClient::Private::onProtocolError(const QString &message)
{
    // 转发错误信号
    emit q->error(message);
    
    // 根据当前操作处理错误
    if (currentOperation == "CONNECT") {
        emit q->connected(false, message);
    } else if (currentOperation == "LIST") {
        //emit q->fileListReceived(false, QList<QFileInfo>(), message);
    } else if (currentOperation == "RETR") {
        finishFileTransfer(false, message);
    } else if (currentOperation == "STOR") {
        finishFileTransfer(false, message);
    } else if (currentOperation == "DELE") {
        emit q->deleteFinished(false, currentRemoteFile, message);
    }
}


    void FtpClient::Private::sendNextCommand()
    {
        if (pendingCommand.isEmpty())
            return;
        
        if (pendingCommand == "LIST") {
            ftpProtocol->sendLIST(pendingCommandArg);
        } else if (pendingCommand == "RETR") {
            ftpProtocol->sendRETR(pendingCommandArg, currentLocalFile);
        } else if (pendingCommand == "STOR") {
            ftpProtocol->sendSTOR(pendingCommandArg);
        }
        
        // 清空待执行命令
        pendingCommand.clear();
        pendingCommandArg.clear();
    }

void FtpClient::Private::doChangeDirectory()
{
    FTP_CLIENT_DEBUG_FMT("尝试切换目录到: %s", pendingCommandArg.toUtf8().constData());
    
    if (!ftpProtocol->sendCWD(pendingCommandArg)) {
        emit q->directoryChanged(false, pendingCommandArg, "发送CWD命令失败");
        pendingCommand.clear();
        pendingCommandArg.clear();
        return;
    }
    
    // 命令已发送，等待响应
}

void FtpClient::Private::doConnect()
{
    // 连接到服务器
    if (ftpProtocol->connectToHost(currentHost, currentPort)) {
        // 连接成功，等待220响应
    } else {
        emit q->connected(false, "连接服务器失败");
    }
}

void FtpClient::Private::doListFiles(const QString &path)
{
    currentOperation = "LIST";
    pendingCommand = "LIST";
    pendingCommandArg = path;
    receivedFileList.clear();
}

void FtpClient::Private::doDownload(const QString &remoteFile, const QString &localPath,qint64 fileSize)
{
    currentRemoteFile = remoteFile;
    currentLocalFile = localPath;
    currentOperation = "RETR";
    pendingCommand = "RETR";
    pendingCommandArg = remoteFile;
    totalTransferSize = fileSize; // 设置已知的文件大小
}

void FtpClient::Private::doUpload(const QString &localFile, const QString &remotePath)
{
    currentLocalFile = localFile;
    
    // 获取文件名
    QFileInfo fileInfo(localFile);
    currentRemoteFile = fileInfo.fileName();
    
    currentOperation = "STOR";
    pendingCommand = "STOR";
    if (!remotePath.endsWith("/")) {
        pendingCommandArg = remotePath+ "/" + currentRemoteFile;
    }
    else {
        pendingCommandArg = remotePath + currentRemoteFile;
    }
}

void FtpClient::Private::doDelete(const QString &fileName)
{
    currentRemoteFile = fileName;
    ftpProtocol->sendDELE(fileName);
}

void FtpClient::Private::startFileTransfer()
{
    if (currentOperation == "RETR") {
        // 下载操作，打开本地文件准备写入
#if 0  //file operation moved to FtpProtocol
        currentTransferFile = new QFile(currentLocalFile);
        if (!currentTransferFile->open(QIODevice::WriteOnly)) {
            emit q->error("无法打开本地文件: " + currentTransferFile->errorString());
            finishFileTransfer(false, "无法打开本地文件");
            return;
        }
        transferredSize = 0;
#endif
    } else if (currentOperation == "STOR") {
        // 上传操作，打开本地文件准备读取
        currentTransferFile = new QFile(currentLocalFile);
        if (!currentTransferFile->open(QIODevice::ReadOnly)) {
            emit q->error("无法打开本地文件: " + currentTransferFile->errorString());
            finishFileTransfer(false, "无法打开本地文件");
            return;
        }
        totalTransferSize = currentTransferFile->size(); // 设置上传文件总大小
        transferredSize = 0;
        // 对于上传操作，开始读取文件并发送数据
        readAndSendFileData();
    }
}

// 新增方法，用于上传时读取文件并发送数据
void FtpClient::Private::readAndSendFileData()
{
    if (currentOperation == "STOR" && currentTransferFile) {
        // 读取文件数据
        QByteArray buffer = currentTransferFile->read(4096);
        if (!buffer.isEmpty()) {
            // 在工作线程中发送数据
            QMetaObject::invokeMethod(ftpProtocol, [this, buffer]() {
                ftpProtocol->dataSocket()->write(buffer);
                ftpProtocol->dataSocket()->flush();

                // 在UI线程中更新进度
                QMetaObject::invokeMethod(this, [this, buffer]() {
                    transferredSize += buffer.size();
                    emit q->uploadProgress(transferredSize, totalTransferSize);

                    // 继续读取和发送数据
                    if (transferredSize < totalTransferSize) {
                        readAndSendFileData();
                    }
                    else {
                        // 文件上传完成，只在PASV2模式下通过命令通道发送FISTOR命令并带上文件长度
                        if (usePasv && usePasv2) {
                            QMetaObject::invokeMethod(ftpProtocol, [this]() {
                                // 构建FISTOR命令，格式：FISTOR <文件长度>
                                QString fistorCommand = QString("FISTOR %1").arg(totalTransferSize);
                                ftpProtocol->sendCommand(fistorCommand);
                                }, Qt::QueuedConnection);

                        }
                        else {
                            QMetaObject::invokeMethod(ftpProtocol, [this]() {
                                ftpProtocol->closeDataConnection();
                                }, Qt::QueuedConnection);
                        }
                    }
                    }, Qt::QueuedConnection);
                }, Qt::QueuedConnection);
        }
        else {
            // 文件读取完毕
            if (transferredSize >= totalTransferSize) {
                // 文件上传完成，只在PASV2模式下通过命令通道发送FISTOR命令并带上文件长度
                if (usePasv && usePasv2) {
                    QMetaObject::invokeMethod(ftpProtocol, [this]() {
                        // 构建FISTOR命令，格式：FISTOR <文件长度>
                        QString fistorCommand = QString("FISTOR %1").arg(totalTransferSize);
                        ftpProtocol->sendCommand(fistorCommand);
                        }, Qt::QueuedConnection);
                }
            }
        }
    }
}

void FtpClient::Private::handleDataTransfer()
{
    // 这里应该连接数据套接字的readyRead信号来处理数据传输
    // 简化实现，实际应用中需要更复杂的处理
    if (currentOperation == "LIST") {
        // 处理文件列表数据
        // 实际应用中需要解析FTP LIST格式的数据
    } else if (currentOperation == "RETR") {
        // 处理下载数据
        // 实际应用中需要从数据套接字读取数据并写入文件
    } else if (currentOperation == "STOR") {
        // 处理上传数据
        if (currentTransferFile) {
            // 从文件读取数据并写入数据套接字
            QByteArray buffer = currentTransferFile->read(4096);
            if (!buffer.isEmpty()) {
                ftpProtocol->dataSocket()->write(buffer);
                transferredSize += buffer.size();
            }
            
            // 检查是否上传完成
            // 在handleDataTransfer方法中
            if (transferredSize >= totalTransferSize) {
            // 文件上传完成，只在PASV2模式下通过命令通道发送FISTOR命令并带上文件长度
            if (usePasv && usePasv2) {
            // 构建FISTOR命令，格式：FISTOR <文件长度>
            QString fistorCommand = QString("FISTOR %1").arg(totalTransferSize);
            ftpProtocol->sendCommand(fistorCommand);
            }
            
            // 完成文件传输，但在PASV2模式下不关闭数据连接
            finishFileTransfer(true, "上传成功");
            }
        }
    }
}

void FtpClient::Private::finishFileTransfer(bool success, const QString &message)
{
    // 关闭文件
    if (currentTransferFile) {
        currentTransferFile->close();
        delete currentTransferFile;
        currentTransferFile = nullptr;
    }
    
    // 只在PASV2模式下保持数据连接，其他模式下关闭
    if (!usePasv2) {
        QMetaObject::invokeMethod(ftpProtocol, [this]() {
            ftpProtocol->closeDataConnection();
            }, Qt::QueuedConnection);
    }
    
    // 发送完成信号
    if (currentOperation == "RETR") {
        FTP_CLIENT_DEBUG_FMT("下载完成，文件:%s", currentRemoteFile.toUtf8().constData());
        emit q->downloadFinished(success, currentRemoteFile, message);
    } else if (currentOperation == "STOR") {
        FTP_CLIENT_DEBUG_FMT("上传完成，文件:%s", currentRemoteFile.toUtf8().constData());
        emit q->uploadFinished(success, currentRemoteFile, message);
    }
}

void FtpClient::Private::onListDataReceived(const QList<QStringList> &fileInfoList)
{
    FTP_CLIENT_DEBUG_FMT("收到文件列表，共%d个条目", fileInfoList.size());
    // 保存接收到的文件列表数据
    receivedFileList = fileInfoList;
    emit q->fileListReceived(true, fileInfoList, "文件列表获取成功");
}

void FtpClient::Private::onFileDataReceived(const QByteArray &data)
{
    FTP_CLIENT_DEBUG_FMT("收到文件数据:%lld字节", (long long)data.size());
    // 处理下载数据
    if (currentOperation == "RETR" && currentTransferFile) {
        QMutexLocker locker(&mutex);
        currentTransferFile->write(data);
        transferredSize += data.size();
        emit q->downloadProgress(transferredSize, totalTransferSize);
        if (totalTransferSize!=0 && transferredSize >= totalTransferSize && usePasv2) {
            finishFileTransfer(true, "下载完成");
        }
    }
}

void FtpClient::Private::onControlConnectionClosed()
{
    FTP_CLIENT_DEBUG("控制连接关闭");
    emit q->disconnected();
}

void FtpClient::Private::onDownloadProgress(qint64 downloaded, QString filename)
{
    FTP_CLIENT_DEBUG_FMT("下载进度:%s - %lld/%lld字节",
        filename.toUtf8().constData(),
        (long long)downloaded,
        (long long)totalTransferSize);

    if (downloaded >= totalTransferSize) {
        finishFileTransfer(true, "下载成功");
        QMetaObject::invokeMethod(ftpProtocol, "onDownloadFileFinish", Qt::QueuedConnection);
        FTP_CLIENT_DEBUG("download finish");
    }
    emit q->downloadProgress(downloaded, totalTransferSize);
}

void FtpClient::Private::onDataConnectionReady()
{
    QMetaObject::invokeMethod(ftpProtocol, [this]() {
        sendNextCommand();
        }, Qt::QueuedConnection);
}

// FtpClient实现
// 在FtpClient构造函数中连接信号
FtpClient::FtpClient(QObject *parent)
    : QObject(parent)
{
    d = new Private(this);
}

FtpClient::~FtpClient()
{
    delete d;
}

void FtpClient::setUsePasv(bool usePasv)
{
    d->usePasv = usePasv;
}

bool FtpClient::isUsingPasv()
{
    return d->usePasv;
}

void FtpClient::connectToServer(const QString &host, const QString &username, const QString &password, int port)
{
    FTP_CLIENT_DEBUG_FMT("请求连接到服务器:%s:%d，用户名:%s",
        host.toUtf8().constData(),
        port,
        username.toUtf8().constData());
    // 保存连接信息
    d->currentHost = host;
    d->currentUsername = username;
    d->currentPassword = password;
    d->currentPort = port;
    d->currentOperation = "CONNECT";
    
    // 异步执行连接
    QMetaObject::invokeMethod(d->ftpProtocol, [this]() {
        if (d->ftpProtocol->connectToHost(d->currentHost, d->currentPort)) {
            // 连接成功，等待220响应
        } else {
            emit connected(false, "连接服务器失败");
        }
    }, Qt::QueuedConnection);
}

void FtpClient::disconnectFromServer()
{
    FTP_CLIENT_DEBUG("请求断开服务器连接");
    // 异步执行断开连接
    QMetaObject::invokeMethod(d->ftpProtocol, [this]() {
        d->ftpProtocol->sendQUIT();
        d->ftpProtocol->disconnectFromHost();
        d->isConnected = false;
        emit disconnected();
    }, Qt::QueuedConnection);
}

void FtpClient::listFiles(const QString &path)
{
    if (!d->isConnected) {
        FTP_CLIENT_DEBUG("错误: 未连接到服务器");
        emit error("未连接到服务器");
        return;
    }
    FTP_CLIENT_DEBUG_FMT("请求列出文件，路径:%s", path.toUtf8().constData());
    d->doListFiles(path);

    // 使用新方法来设置数据连接模式
    QMetaObject::invokeMethod(d->ftpProtocol, "setupDataConnectionMode",
        Qt::QueuedConnection,
        Q_ARG(bool, d->usePasv),
        Q_ARG(bool, d->usePasv2));
}

void FtpClient::downloadFile(const QString &remoteFile, const QString &localPath)
{
    downloadFile(remoteFile, localPath, 0);
}

void FtpClient::downloadFile(const QString& remoteFile, const QString& localPath, qint64 fileSize)
{
    if (!d->isConnected) {
        FTP_CLIENT_DEBUG("错误: 未连接到服务器");
        emit error("未连接到服务器");
        return;
    }
    FTP_CLIENT_DEBUG_FMT("请求下载文件:%s到:%s",
        remoteFile.toUtf8().constData(),
        localPath.toUtf8().constData());
    d->doDownload(remoteFile, localPath,fileSize);

    // 使用新方法来设置数据连接模式
    QMetaObject::invokeMethod(d->ftpProtocol, "setupDataConnectionMode",
        Qt::QueuedConnection,
        Q_ARG(bool, d->usePasv),
        Q_ARG(bool, d->usePasv2));
}

void FtpClient::uploadFile(const QString &localFile, const QString &remotePath)
{
    if (!d->isConnected) {
        FTP_CLIENT_DEBUG("错误: 未连接到服务器");
        emit error("未连接到服务器");
        return;
    }
    FTP_CLIENT_DEBUG_FMT("请求上传文件:%s到:%s",
        localFile.toUtf8().constData(),
        remotePath.toUtf8().constData());

    d->doUpload(localFile, remotePath);

    // 使用新方法来设置数据连接模式
    QMetaObject::invokeMethod(d->ftpProtocol, "setupDataConnectionMode",
        Qt::QueuedConnection,
        Q_ARG(bool, d->usePasv),
        Q_ARG(bool, d->usePasv2));
}

void FtpClient::deleteFile(const QString &fileName)
{
    if (!d->isConnected) {
        FTP_CLIENT_DEBUG("错误: 未连接到服务器");
        emit error("未连接到服务器");
        return;
    }
    FTP_CLIENT_DEBUG_FMT("请求删除文件:%s", fileName.toUtf8().constData());
    d->currentOperation = "DELE";
    d->currentRemoteFile = fileName;
    
    QMetaObject::invokeMethod(d, "doDelete", Qt::QueuedConnection, Q_ARG(QString, fileName));
}

void FtpClient::changeDirectory(const QString &directory)
{
    if (!d->isConnected) {
        FTP_CLIENT_DEBUG("错误: 未连接到服务器");
        emit error("未连接到服务器");
        emit directoryChanged(false, directory, "未连接到服务器");
        return;
    }
    FTP_CLIENT_DEBUG_FMT("请求切换目录到:%s", directory.toUtf8().constData());
    
    d->pendingCommand = "CWD";
    d->pendingCommandArg = directory;
    
    // 切换到工作线程执行
    QMetaObject::invokeMethod(d, "doChangeDirectory", Qt::QueuedConnection);
}

bool FtpClient::isConnected() const
{
    return d->isConnected;
}

// 必须添加这一行来处理Q_OBJECT宏在.cpp文件中的问题
#include "ftpclient.moc"


//设置是否使用PASV2模式的方法
void FtpClient::setUsePasv2(bool usePasv2)
{
    d->usePasv2 = usePasv2;
}

//获取当前是否使用PASV2模式的方法
bool FtpClient::isUsingPasv2() const
{
    return d->usePasv2;
}
